# author: HuDaoquan
# contact: 1455523026@qq.com
# datetime:2022/5/2 20:24
# software: PyCharm

"""
文件说明：多线程统计多台gitlab服务器指定时间段内用户代码量
"""
import multiprocessing
import threading
from concurrent.futures import ProcessPoolExecutor
from functools import reduce

import gitlab
import datetime
import json
import os
import json

from gevent.threadpool import ThreadPoolExecutor
import threading
import gitlab
import xlwt

ip_token = {
    # '10.39.39.149': 'bzs78Rx4q5szgyxdWtzD',
    '10.39.39.18': 'VJQphpeRXoJQb1yTT-16'
}
start_time = '2022-05-01'
end_time = '2022-06-01'



# 获取project下所有的branche
def getAllBranchByProject(project):
    try:
        branches = project.branches.list()
        return branches
    except:
        return ""


# 获取project和branch下的commit，跳过merge
def getCommitByBranch(project, branch):
    author_commits = []
    detail_map = {}
    commits = project.commits.list(all=True,
                                   query_parameters={'since': start_time, 'until': end_time, 'ref_name': branch.name})
    for commit in commits:
        commit_info = project.commits.get(commit.id)
        title = commit_info.title
        message = commit_info.message
        if ('Merge' in message) or ('Merge' in title):
           print('Merge跳过：'+branch.name+"  "+project.web_url)
           continue
        else:
            author_commits.append(commit_info)
            # 根据email纬度，统计提交数据
            exist_detail = detail_map.get(commit_info.author_email)
            if exist_detail is None:
                detail_map[commit.author_email] = commit_info
            else:
                exist_detail.stats["total"] += commit_info.stats["total"]
                exist_detail.stats["additions"] += commit_info.stats["additions"]
                exist_detail.stats["deletions"] += commit_info.stats["deletions"]
                detail_map[commit_info.author_email] = exist_detail
    return detail_map

class ReturnData(json.JSONEncoder):
    """
      项目成员结构体
    """
    projectCodeDataList = []
    branchMap = {}




def getAuthorCode(project,branch_map,user_map,project_user_commit):

    project_branch_map = {}
    # 获取项目下所有分支
    branches = getAllBranchByProject(project)
    if branches == "":
        pass
    else:
        for branch in branches:
            # 跳过master分支
            if branch.name != "master":
                # 获取当前分支的所有提交,并按邮箱合并代码量
                detail_map = getCommitByBranch(project, branch)
                if len(detail_map)!=0:
                    # branch的map，key为branch名称，value为按照提交者email汇总的，key为email的子map集合
                    project_branch_map[str(project.id)+branch.name] = detail_map
                    branch_map[str(project.id)+branch.name] = detail_map
    description = project.description
    if description is not None:
        description = description.replace("\r\n", "。")
    else:
        description = "无"


    user_commit_map = {}
    # 遍历所有分支
    for key, value_map in project_branch_map.items():
        # 遍历每个分支的所有人的提交
        for author_email, detail in value_map.items():
            exist_detail = user_commit_map.get(author_email)
            if exist_detail is None:
                user_commit_map[detail.author_email] = detail
            else:
                exist_detail.stats["total"] += detail.stats["total"]
                exist_detail.stats["additions"] += detail.stats["additions"]
                exist_detail.stats["deletions"] += detail.stats["deletions"]
                user_commit_map[detail.author_email] = exist_detail
    # print(user_commit_map)
    for key, value_map in user_commit_map.items():
        projectCodeData = {}
        projectCodeData["projectId"] = project.id
        projectCodeData["projectDescription"] = description
        projectCodeData["projectUrl"] = project.web_url
        try:
            name =user_map[key]
        except:
            name="未知/离职"
        projectCodeData["username"] = name
        projectCodeData["email"] = key
        projectCodeData["total"] = value_map.stats["total"]
        projectCodeData["additions"] = value_map.stats["additions"]
        projectCodeData["deletions"] = value_map.stats["deletions"]
        projectCodeData["startTime"] = start_time
        projectCodeData["endTime"] = end_time
        project_user_commit.append(projectCodeData)
        # value.author_email, value.author_name, value.total, value.additions, value.deletions
    return project_user_commit


def coutAuthCode(branch_map):
    final_commit_map = {}
    # 遍历所有分支branch map，并按照提交者email进行汇总
    for key, value_map in branch_map.items():
        for author_email, detail in value_map.items():
            exist_detail = final_commit_map.get(detail.author_email)
            if exist_detail is None:
                final_commit_map[detail.author_email] = detail
            else:
                exist_detail.total += detail.total
                exist_detail.additions += detail.additions
                exist_detail.deletions += detail.deletions
                final_commit_map[detail.author_email] = exist_detail
    return final_commit_map



# 写入execl
def writeExcel(excelPath, data):
    print("开始写文件")
    # 创建文件
    if excelPath.endswith("/"):
        if not os.path.exists(excelPath):
            os.makedirs(excelPath)
    else:
        folder_path = excelPath[0:excelPath.rfind('/') + 1]
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)

    workbook = xlwt.Workbook()
    # 获取第一个sheet页
    sheet = workbook.add_sheet('git')
    row0 = ['项目id', '项目描述', '项目地址', '用户名', '用户邮箱', '总计变更量', '新增代码量', '删除代码量', '开始日期', '结束日期']
    for i in range(0, len(row0)):
        sheet.write(0, i, row0[i])

    for i in range(0, len(data)):
        recode = data[i]
        j = 0
        sheet.write(i + 1, j, recode['projectId'])
        sheet.write(i + 1, j + 1, recode['projectDescription'])
        sheet.write(i + 1, j + 2, recode['projectUrl'])
        sheet.write(i + 1, j + 3, recode['username'])
        sheet.write(i + 1, j + 4, recode['email'])
        sheet.write(i + 1, j + 5, recode['total'])
        sheet.write(i + 1, j + 6, recode['additions'])
        sheet.write(i + 1, j + 7, recode['deletions'])
        sheet.write(i + 1, j + 8, recode['startTime'])
        sheet.write(i + 1, j + 9, recode['endTime'])
    workbook.save(excelPath)

# 将传入的提交记录按邮箱汇总相加
def calculate(data):
    record = {}
    addcount = 0
    deletecount = 0
    totaolcount = 0
    for i in data:
        # print(i)
        addcount += int(i['additions'])
        deletecount += int(i['deletions'])
        totaolcount += int(i['total'])
    record['additions'] = addcount
    record['deletions'] = deletecount
    record['total'] = totaolcount
    return record


if __name__ == '__main__':
    # 当前时间
    start= datetime.datetime.now()
    print(start)
    data = []
    branch_map={}
    users=[]
    thread_list = []
    # 获取所有用户信息
    user_map = {}
    project_user_commit=[]
    for gitlabAddress, gitlabToken in ip_token.items():
        gl = gitlab.Gitlab('http://' + gitlabAddress, private_token=gitlabToken, api_version='4')

        usertemp = gl.users.list(all=True)
        users.extend(usertemp)
        for user in usertemp:
            user_map[user.email]=user.name
        # 先把所有项目查出来，all=True 一定要加上。不然查出来的只有第一页项目,按最后活跃时间排序
        projects = gl.projects.list(all=True, order_by='last_activity_at')
        # 遍历每一个项目
        for project in projects:
            description = project.description
            if description is not None:
                description = description.replace("\r\n", "。")
            else:
                description="无"
            print("开始遍历项目："+project.web_url+" 描述："+description)
            # branches = getAllBranchByProject(project)
            # for j in branches:
                # 跳过master分支
                # if(j.name!="master"):
            # 多线程
            t = threading.Thread(target=getAuthorCode, args=(project,branch_map,user_map,project_user_commit))
            thread_list.append(t)
            # 单线程
            # getAuthorCode(project,branch_map,user_map,project_user_commit)
    for threadname in thread_list: threadname.start()
    for threadname in thread_list: threadname.join()
    projectUserCommit = "./dist/projectUser%s至%s统计时间%s.xls" % (start_time,end_time,'{:%Y%m%d%H%M%S}'.format(start))
    writeExcel(projectUserCommit, project_user_commit)
    end = datetime.datetime.now()
    print(end)
    print("耗时（秒）:" + str((end - start).seconds))
